// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.

// [Guard]
#ifndef _ASMJIT_BASE_RUNTIME_H
#define _ASMJIT_BASE_RUNTIME_H

// [Dependencies - AsmJit]
#include "../base/vmem.h"

// [Api-Begin]
#include "../apibegin.h"

namespace asmjit {

// ============================================================================
// [Forward Declarations]
// ============================================================================

struct Assembler;
struct CpuInfo;

//! \addtogroup asmjit_base
//! \{

// ============================================================================
// [asmjit::RuntimeType]
// ============================================================================

ASMJIT_ENUM(RuntimeType) {
  kRuntimeTypeNone = 0,
  kRuntimeTypeJit = 1,
  kRuntimeTypeRemote = 2
};

// ============================================================================
// [asmjit::Runtime]
// ============================================================================

//! Base runtime.
struct ASMJIT_VIRTAPI Runtime {
  ASMJIT_NO_COPY(Runtime)

  // --------------------------------------------------------------------------
  // [Construction / Destruction]
  // --------------------------------------------------------------------------

  //! Create a `Runtime` instance.
  ASMJIT_API Runtime();
  //! Destroy the `Runtime` instance.
  ASMJIT_API virtual ~Runtime();

  // --------------------------------------------------------------------------
  // [Accessors]
  // --------------------------------------------------------------------------

  //! Get runtime type.
  ASMJIT_INLINE uint32_t getRuntimeType() const { return _runtimeType; }

  //! Get whether the runtime has a base address.
  ASMJIT_INLINE bool hasBaseAddress() const { return _baseAddress != kNoBaseAddress; }
  //! Get the base address.
  ASMJIT_INLINE Ptr getBaseAddress() const { return _baseAddress; }

  // --------------------------------------------------------------------------
  // [Interface]
  // --------------------------------------------------------------------------

  //! Get CPU information.
  virtual const CpuInfo* getCpuInfo() = 0;

  //! Get stack alignment of target runtime.
  virtual uint32_t getStackAlignment() = 0;

  //! Allocate a memory needed for a code generated by `assembler` and
  //! relocate it to the target location.
  //!
  //! The beginning of the memory allocated for the function is returned in
  //! `dst`. Returns Status code as \ref ErrorCode, on failure `dst` is set to
  //! `nullptr`.
  virtual Error add(void** dst, Assembler* assembler) = 0;

  //! Release memory allocated by `add`.
  virtual Error release(void* p) = 0;

  // --------------------------------------------------------------------------
  // [Members]
  // --------------------------------------------------------------------------

  //! Maximum size of the code that can be added to the runtime (0=unlimited).
  size_t _sizeLimit;
  //! Base address (-1 means no base address).
  Ptr _baseAddress;

  //! Type of the runtime.
  uint8_t _runtimeType;
  //! Type of the allocation.
  uint8_t _allocType;
  //! \internal
  uint8_t _reserved[sizeof(intptr_t) - 2];
};

// ============================================================================
// [asmjit::HostRuntime]
// ============================================================================

//! Base runtime for JIT code generation.
struct ASMJIT_VIRTAPI HostRuntime : public Runtime {
  ASMJIT_NO_COPY(HostRuntime)

  // --------------------------------------------------------------------------
  // [Construction / Destruction]
  // --------------------------------------------------------------------------

  //! Create a `HostRuntime` instance.
  ASMJIT_API HostRuntime();
  //! Destroy the `HostRuntime` instance.
  ASMJIT_API virtual ~HostRuntime();

  // --------------------------------------------------------------------------
  // [Interface]
  // --------------------------------------------------------------------------

  ASMJIT_API virtual const CpuInfo* getCpuInfo();
  ASMJIT_API virtual uint32_t getStackAlignment();

  //! Flush an instruction cache.
  //!
  //! This member function is called after the code has been copied to the
  //! destination buffer. It is only useful for JIT code generation as it
  //! causes a flush of the processor cache.
  //!
  //! Flushing is basically a NOP under X86/X64, but is needed by architectures
  //! that do not have a transparent instruction cache.
  //!
  //! This function can also be overridden to improve compatibility with tools
  //! such as Valgrind, however, it's not an official part of AsmJit.
  ASMJIT_API virtual void flush(void* p, size_t size);
};

// ============================================================================
// [asmjit::StaticRuntime]
// ============================================================================

//! JIT static runtime.
//!
//! JIT static runtime can be used to generate code to a memory location that
//! is known.
struct ASMJIT_VIRTAPI StaticRuntime : public HostRuntime {
  ASMJIT_NO_COPY(StaticRuntime)

  // --------------------------------------------------------------------------
  // [Construction / Destruction]
  // --------------------------------------------------------------------------

  //! Create a `StaticRuntime` instance.
  //!
  //! The `address` specifies a fixed target address, which will be used as a
  //! base address for relocation, and `sizeLimit` specified the maximum size
  //! of a code that can be copied to it. If there is no limit `sizeLimit`
  //! should be zero.
  ASMJIT_API StaticRuntime(void* baseAddress, size_t sizeLimit = 0);
  //! Destroy the `StaticRuntime` instance.
  ASMJIT_API virtual ~StaticRuntime();

  // --------------------------------------------------------------------------
  // [Accessors]
  // --------------------------------------------------------------------------

  //! Get the base address.
  ASMJIT_INLINE Ptr getBaseAddress() const { return _baseAddress; }

  //! Get the maximum size of the code that can be relocated/stored in the target.
  //!
  //! Returns zero if unlimited.
  ASMJIT_INLINE size_t getSizeLimit() const { return _sizeLimit; }

  // --------------------------------------------------------------------------
  // [Interface]
  // --------------------------------------------------------------------------

  ASMJIT_API virtual Error add(void** dst, Assembler* assembler);
  ASMJIT_API virtual Error release(void* p);
};

// ============================================================================
// [asmjit::JitRuntime]
// ============================================================================

//! JIT runtime.
struct ASMJIT_VIRTAPI JitRuntime : public HostRuntime {
  ASMJIT_NO_COPY(JitRuntime)

  // --------------------------------------------------------------------------
  // [Construction / Destruction]
  // --------------------------------------------------------------------------

  //! Create a `JitRuntime` instance.
  ASMJIT_API JitRuntime();
  //! Destroy the `JitRuntime` instance.
  ASMJIT_API virtual ~JitRuntime();

  // --------------------------------------------------------------------------
  // [Accessors]
  // --------------------------------------------------------------------------

  //! Get the type of allocation.
  ASMJIT_INLINE uint32_t getAllocType() const { return _allocType; }
  //! Set the type of allocation.
  ASMJIT_INLINE void setAllocType(uint32_t allocType) { _allocType = allocType; }

  //! Get the virtual memory manager.
  ASMJIT_INLINE VMemMgr* getMemMgr() const { return const_cast<VMemMgr*>(&_memMgr); }

  // --------------------------------------------------------------------------
  // [Interface]
  // --------------------------------------------------------------------------

  ASMJIT_API virtual Error add(void** dst, Assembler* assembler);
  ASMJIT_API virtual Error release(void* p);

  // --------------------------------------------------------------------------
  // [Members]
  // --------------------------------------------------------------------------

  //! Virtual memory manager.
  VMemMgr _memMgr;
};

//! \}

} // asmjit namespace

// [Api-End]
#include "../apiend.h"

// [Guard]
#endif // _ASMJIT_BASE_RUNTIME_H
